//
//  GameEngine.swift
//  ChineseChess
//
//  Created by 左忠飞 on 2021/1/22.
//

import UIKit

protocol GameEngineDelegate {
    func gameOver(redWin:Bool)
    //当行棋的一方改变时调用
    func couldRedMove(red:Bool)
}

class GameEngine: NSObject,ChessBoardDelegate {
    
    //游戏结束
    func gameOver(redWin: Bool) {
        isStarting = false
        //将胜负状态传递给界面
        if delegate != nil {
            delegate?.gameOver(redWin: redWin)
        }
    }
    
    //当用户点击某个棋子后的回调
    func chessItemClick(item: ChessItem) {
        //判断点击的棋子是否属于应该行棋的一方
        if shouldRedMove {
            if item.isRed {
                gameBoard?.cancelAllSelect()
                item.setSelectedStated()
            }else{
                return
            }
        }else{
            if !item.isRed {
                gameBoard?.cancelAllSelect()
                item.setSelectedStated()
            }else{
                return
            }
        }
        //进行行棋算法
        checkCanMove(item: item)
    }
    
    //一方行完棋之后,换另一方行棋
    func chessMoveEnd() {
        shouldRedMove = !shouldRedMove
        gameBoard?.cancelAllSelect()
    }
    
    //当前游戏棋盘
    var gameBoard:ChessBoard?
    //设置是否红方先走,默认红方先走
    var redFirstMove = true
    //标记当前需要行棋的一方
    var shouldRedMove = true
    //代理
    var delegate:GameEngineDelegate?
    //开始游戏的标记
    var isStarting = false
    
    //棋子的路径集合
    let checkMoveDict:[String:[[(Int,Int)]]] = [
        //第一个元素是没过界之前的可行算法,第二个是过界之后的
        "兵":[[(0,-1)],[(0,-1),(-1,0),(1,0)]],
        "卒":[[(0,-1)],[(0,-1),(-1,0),(1,0)]],
        "将":[[(0,1),(0,-1),(1,0),(-1,0)]],
        "帥":[[(0,1),(0,-1),(1,0),(-1,0)]],
        "仕":[[(1,1),(-1,-1),(-1,1),(1,-1)]],
        "士":[[(1,1),(-1,-1),(-1,1),(1,-1)]],
        "相":[[(2,2),(-2,-2),(-2,2),(2,-2)]],
        "象":[[(2,2),(-2,-2),(-2,2),(2,-2)]],
        "马":[[(1,2),(1,-2),(2,1),(2,-1),(-1,2),(-1,-2),(-2,1),(-2,-1)]],
        "馬":[[(1,2),(1,-2),(2,1),(2,-1),(-1,2),(-1,-2),(-2,1),(-2,-1)]]

    ]
    
    init(board:ChessBoard) {
        gameBoard = board
        super.init()
        gameBoard?.delegate = self
    }
    
    //开始游戏的方法
    func startGame(){
        isStarting = true
        gameBoard?.reStartGame()
        shouldRedMove = redFirstMove
        if delegate != nil {
            delegate?.couldRedMove(red: shouldRedMove)
        }
    }
    
    //设置先行棋的一方
    func setRedFirstMove(red:Bool){
        redFirstMove = red
        shouldRedMove = red
    }
    
    //检测可以移动的位置
    func checkCanMove(item:ChessItem) {
        
        if (item.title(for: .normal) == "兵" ||
            item.title(for: .normal) == "卒") {
            checkSoldierCanMove(item: item)
        }else if (item.title(for: .normal) == "士" ||
            item.title(for: .normal) == "仕"){
            checkShiCanMove(item: item)
        }else if (item.title(for: .normal) == "将" ||
            item.title(for: .normal) == "帥"){
            checkGeneralCanMove(item: item)
        }else if (item.title(for: .normal) == "相" ||
            item.title(for: .normal) == "象"){
            checkXiangCanMove(item: item)
        }else if (item.title(for: .normal) == "马" ||
            item.title(for: .normal) == "馬"){
            checkHorseCanMove(item: item)
        }else if (item.title(for: .normal) == "车" ||
            item.title(for: .normal) == "車"){
            checkCarCanMove(item: item)
        }else if (item.title(for: .normal) == "炮"){
            checkCannonCanMove(item: item)
        }
        
    }
    
    //兵 卒 行棋算法
    func checkSoldierCanMove(item:ChessItem){
        if (item.title(for: .normal) == "兵") {
            //获取棋子在二维矩阵中的位置
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            //如果没过界,那么 兵 只能前进
            var wantMove = Array<(Int,Int)>()
            if position.1 > 4 {
                wantMove = [(position.0,position.1 - 1)]
            }else{
                //左右前
                if position.0 > 0 {
                    wantMove.append((position.0-1,position.1))
                }
                if position.0 < 8 {
                    wantMove.append((position.0+1,position.1))
                }
                if position.1 > 0 {
                    wantMove.append((position.0,position.1-1))
                }
            }
            //交换给棋盘类进行移动提示
            gameBoard?.wantMoveItem(positions: wantMove, item: item)
        }
        
        if (item.title(for: .normal) == "卒") {
            //获取棋子在二维矩阵中的位置
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            //如果没过界,那么 卒 只能前进
            var wantMove = Array<(Int,Int)>()
            if position.1 < 5 {
                wantMove = [(position.0,position.1+1)]
            }else{
                //左右前
                if position.0 > 0 {
                    wantMove.append((position.0-1,position.1))
                }
                if position.0 < 8 {
                    wantMove.append((position.0+1,position.1))
                }
                if position.1 < 9 {
                    wantMove.append((position.0,position.1+1))
                }
            }
            //交换给棋盘类进行移动提示
            gameBoard?.wantMoveItem(positions: wantMove, item: item)
        }
    }
    
    //士 仕 行棋算法
    func checkShiCanMove(item:ChessItem){
        if item.title(for: .normal) == "士"{
            //获取棋子在二维矩阵中的位置
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            //士在将格内沿对角线行棋
            var wangMove = Array<(Int,Int)>()
            //左上,右上,左下,右下四个方向行棋
            if position.0 < 5 && position.1 > 7{
                wangMove.append((position.0+1,position.1-1))
            }
            if position.0 > 3 && position.1 < 9{
                wangMove.append((position.0-1,position.1+1))
            }
            if position.0 > 3 && position.1 > 7{
                wangMove.append((position.0-1,position.1-1))
            }
            if position.0 < 5 && position.1 < 9{
                wangMove.append((position.0+1,position.1+1))
            }
            gameBoard?.wantMoveItem(positions: wangMove, item: item)
        }else if item.title(for: .normal) == "仕"{
            //获取棋子在二维矩阵中的位置
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            //士在将格内沿对角线行棋
            var wangMove = Array<(Int,Int)>()
            //左上,右上,左下,右下四个方向行棋
            if position.0 < 5 && position.1 < 2{
                wangMove.append((position.0+1,position.1+1))
            }
            if position.0 > 3 && position.1 > 0{
                wangMove.append((position.0-1,position.1-1))
            }
            if position.0 > 3 && position.1 < 2{
                wangMove.append((position.0-1,position.1+1))
            }
            if position.0 < 5 && position.1 > 0{
                wangMove.append((position.0+1,position.1-1))
            }
            gameBoard?.wantMoveItem(positions: wangMove, item: item)
        }
    }
    
    //将 帥 行棋算法
    func checkGeneralCanMove(item:ChessItem){
        if item.title(for: .normal) == "将"{
            //获取棋子在二维矩阵中的位置
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            //将在将格内上下左右行棋
            var wangMove = Array<(Int,Int)>()
            //上,下,左,右四个方向行棋
            if position.1 < 2{
                wangMove.append((position.0,position.1+1))
            }
            if position.1 > 0{
                wangMove.append((position.0,position.1-1))
            }
            if position.0 < 5{
                wangMove.append((position.0+1,position.1))
            }
            if position.0 > 3{
                wangMove.append((position.0-1,position.1))
            }
            gameBoard?.wantMoveItem(positions: wangMove, item: item)
        }else if item.title(for: .normal) == "帥"{
            //获取棋子在二维矩阵中的位置
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            //帥在将格内上下左右行棋
            var wangMove = Array<(Int,Int)>()
            //上,下,左,右四个方向行棋
            if position.1 < 9{
                wangMove.append((position.0,position.1+1))
            }
            if position.1 > 7{
                wangMove.append((position.0,position.1-1))
            }
            if position.0 < 5{
                wangMove.append((position.0+1,position.1))
            }
            if position.0 > 3{
                wangMove.append((position.0-1,position.1))
            }
            gameBoard?.wantMoveItem(positions: wangMove, item: item)
        }
    }
    
    //相 象 行棋算法
    func checkXiangCanMove(item:ChessItem){
        if item.title(for: .normal) == "相" {
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            var wantMove = Array<(Int,Int)>()
            let redList = gameBoard!.getAllRedMatrixList()
            let greenList = gameBoard!.getAllGreenMatrixList()
            
            //左上,左下,右上,右下
            if position.0 - 2 >= 0 && position.1 - 2 > 4 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1-1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1-1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0-2,position.1-2))
                }
            }
            if position.0+2<=8 && position.1+2<=9 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1+1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1+1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0+2,position.1+2))
                }
            }
            if position.0+2<=8 && position.1-2>4 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1-1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1-1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0+2,position.1-2))
                }
            }
            if position.0-2>=0 && position.1+2<=9 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1+1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1+1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0-2,position.1+2))
                }
            }
            gameBoard?.wantMoveItem(positions: wantMove, item: item)

        }else if item.title(for: .normal) == "象" {
            let position = gameBoard!.transfromPositionToMatrix(item: item)
            var wantMove = Array<(Int,Int)>()
            let redList = gameBoard!.getAllRedMatrixList()
            let greenList = gameBoard!.getAllGreenMatrixList()
            
            //左上,左下,右上,右下
            if position.0 - 2 >= 0 && position.1 - 2 >= 0 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1-1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1-1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0-2,position.1-2))
                }
            }
            if position.0+2<=8 && position.1+2<=4 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1+1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1+1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0+2,position.1+2))
                }
            }
            if position.0+2<=8 && position.1-2>=0 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1-1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0+1,position.1-1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0+2,position.1-2))
                }
            }
            if position.0-2>=0 && position.1+2<=4 {
                //判断是否有棋子塞象眼
                if redList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1+1)
                }) || greenList.contains(where: { (pos) -> Bool in
                    return pos == (position.0-1,position.1+1)
                }){
                    //塞象眼,不添加此位置
                }else{
                    wantMove.append((position.0-2,position.1+2))
                }
            }
            gameBoard?.wantMoveItem(positions: wantMove, item: item)
        }
    }
    
    //马 馬 行棋算法
    func checkHorseCanMove(item:ChessItem){
        let position = gameBoard!.transfromPositionToMatrix(item: item)
        var wantMove = Array<(Int,Int)>()
        let redList = gameBoard!.getAllRedMatrixList()
        let greenList = gameBoard!.getAllGreenMatrixList()
        
        //以日字行走,八个方向,上下左右各两个方向
        if position.0-1>=0 && position.1-2>=0 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1-1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1-1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0-1,position.1-2))
            }
        }
        if position.0+1<=8 && position.1-2>=0 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1-1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1-1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0+1,position.1-2))
            }
        }
        if position.0+2<=8 && position.1-1>=0 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0+1,position.1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0+1,position.1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0+2,position.1-1))
            }
        }
        if position.0+2<=8 && position.1+1<=9 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0+1,position.1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0+1,position.1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0+2,position.1+1))
            }
        }
        if position.0+1<=8 && position.1+2<=9 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1+1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1+1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0+1,position.1+2))
            }
        }
        if position.0-1>=0 && position.1+2<=9 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1+1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0,position.1+1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0-1,position.1+2))
            }
        }
        if position.0-2>=0 && position.1+1<=9 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0-1,position.1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0-1,position.1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0-2,position.1+1))
            }
        }
        if position.0-2>=0 && position.1+1>=0 {
            if redList.contains(where: { (pos) -> Bool in
                return pos == (position.0-1,position.1)
            }) || greenList.contains(where: { (pos) -> Bool in
                return pos == (position.0-1,position.1)
            }){
                //拌马腿,不添加此位置
            }else{
                wantMove.append((position.0-2,position.1-1))
            }
        }
        gameBoard?.wantMoveItem(positions: wantMove, item: item)
    }
    
    //车 車 行棋算法(有问题,待完善)
    func checkCarCanMove(item:ChessItem){
        //“车”的行棋规则为走直线且无距离限制，直到遇到己方棋子，或吃掉敌方棋子。
        let position = gameBoard!.transfromPositionToMatrix(item: item)
        var wantMove = Array<(Int,Int)>()
        let redList = gameBoard!.getAllRedMatrixList()
        let greenList = gameBoard!.getAllGreenMatrixList()
        //车可以沿水平方向和竖直方向行棋
        //水平方向分为左和右
        var temP = position
        while temP.0 - 1 >= 0 {
            //如果有棋子则退出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0-1,temP.1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0-1,temP.1)
            })) {
                wantMove.append((temP.0-1,temP.1))
                break
            }else{
                wantMove.append((temP.0-1,temP.1))
            }
            temP.0 -= 1
        }
        
        temP = position
        while temP.0 + 1 <= 8 {
            //如果有棋子则退出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0+1,temP.1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0+1,temP.1)
            })) {
                wantMove.append((temP.0+1,temP.1))
                break
            }else{
                wantMove.append((temP.0+1,temP.1))
            }
            temP.0 += 1
        }
        
        temP = position
        while temP.1 + 1 <= 9 {
            //如果有棋子则退出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1+1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1+1)
            })) {
                wantMove.append((temP.0,temP.1+1))
                break
            }else{
                wantMove.append((temP.0,temP.1+1))
            }
            temP.1 += 1
        }
        
        temP = position
        while temP.1 - 1 >= 0 {
            //如果有棋子则退出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1-1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1-1)
            })) {
                wantMove.append((temP.0,temP.1-1))
                break
            }else{
                wantMove.append((temP.0,temP.1-1))
            }
            temP.1 -= 1
        }
        gameBoard?.wantMoveItem(positions: wantMove, item: item)
    }
    
    //炮 行棋算法
    func checkCannonCanMove(item:ChessItem){
        //“炮”的行棋规则与“车”有些类似，不同的是如果要吃掉敌方棋子，中间必须有一个棋子作为炮台
        let position = gameBoard!.transfromPositionToMatrix(item: item)
        var wantMove = Array<(Int,Int)>()
        let redList = gameBoard!.getAllRedMatrixList()
        let greenList = gameBoard!.getAllGreenMatrixList()
        
        //炮可以沿水平和竖直两个方向行棋
        //水平方向分为左和右
        var temP = position
        var isFirst = true
        
        //当x轴大于0时,说明左边有空位,计算左边可行棋位置
        while temP.0-1>=0 {
            //如果有棋子则找出其后面最近的一刻棋子,之后推出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0-1,temP.1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0-1,temP.1)
            })) {
                if !isFirst {
                    wantMove.append((temP.0-1,temP.1))
                    break
                }
                isFirst = false
            }else{
                if isFirst {
                    wantMove.append((temP.0-1,temP.1))
                }
            }
            temP.0-=1
        }
        temP = position
        isFirst = true
        //当x轴小于9,说明右边有空位,计算右边的可行棋位置
        while temP.0<9 {
            //如果有棋子则找出其后面最近的一刻棋子,之后推出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0+1,temP.1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0+1,temP.1)
            })) {
                if !isFirst {
                    wantMove.append((temP.0+1,temP.1))
                    break
                }
                isFirst = false
            }else{
                if isFirst {
                    wantMove.append((temP.0+1,temP.1))
                }
            }
            temP.0+=1
        }
        temP = position
        isFirst = true
        //当y轴小于9,说明下边有空位,计算下边的可行棋位置
        while temP.1<9 {
            //如果有棋子则找出其后面最近的一刻棋子,之后推出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1+1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1+1)
            })) {
                if !isFirst {
                    wantMove.append((temP.0,temP.1+1))
                    break
                }
                isFirst = false
            }else{
                if isFirst {
                    wantMove.append((temP.0,temP.1+1))
                }
            }
            temP.1+=1
        }
        temP = position
        isFirst = true
        //当y轴大于0,说明上边有空位,计算上边的可行棋位置
        while temP.1>0 {
            //如果有棋子则找出其后面最近的一刻棋子,之后推出循环
            if (redList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1-1)
            })) || (greenList.contains(where: { (pos) -> Bool in
                return pos == (temP.0,temP.1-1)
            })) {
                if !isFirst {
                    wantMove.append((temP.0,temP.1-1))
                    break
                }
                isFirst = false
            }else{
                if isFirst {
                    wantMove.append((temP.0,temP.1-1))
                }
            }
            temP.1-=1
        }
        
        gameBoard?.wantMoveItem(positions: wantMove, item: item)
    }
}
